<script setup lang="ts">
import { ElButton, ElDialog, ElInput, ElMessage, ElTree, ElInputNumber, ElForm, ElFormItem } from 'element-plus'
import { onMounted, ref, reactive, computed, nextTick } from 'vue'
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import GltfZipLoader from './components/GltfZipLoader.vue';

const loadingStatus = ref(false);
const loadError = ref(null);
// const mainCanvasContainer = ref(null);

// --- Your main Three.js Scene Setup ---
// let mainScene, mainCamera, mainRenderer /* ... etc ... */;
// let loadedModel = null;

// 创建 Three.js 相关变量
const canvasRef = ref<HTMLCanvasElement | null>(null)
let scene: THREE.Scene
let camera: THREE.PerspectiveCamera
let renderer: THREE.WebGLRenderer
let cube: THREE.Mesh
let loadedModel: THREE.Object3D | null = null
let controls: OrbitControls
let raycaster: THREE.Raycaster
let mouse: THREE.Vector2

// 选择框相关变量
let selectionBox: THREE.Box3Helper | null = null

// 导入模型相关变量
const importDialogVisible = ref(false)
const modelPath = ref('/classic_muscle_car/scene.gltf')
const isLoading = ref(false)

// 场景树相关变量
const sceneTreeData = ref<any[]>([])
const selectedObject = ref<THREE.Object3D | null>(null)
const treeRef = ref<InstanceType<typeof ElTree> | null>(null)
const currentNodeKey = ref<string | number>('')

// 属性面板相关变量
// 在 objectProps 中添加 visible 属性
const objectProps = reactive({
  name: '',
  type: '',
  visible: true,
  position: { x: 0, y: 0, z: 0 },
  rotation: { x: 0, y: 0, z: 0 },
  scale: { x: 1, y: 1, z: 1 }
})

// 在 updateObjectProps 函数中添加 visible 属性的更新
const updateObjectProps = (object: THREE.Object3D) => {
  objectProps.name = object.name
  objectProps.type = object.type
  objectProps.visible = object.visible

  objectProps.position.x = Number(object.position.x.toFixed(3))
  objectProps.position.y = Number(object.position.y.toFixed(3))
  objectProps.position.z = Number(object.position.z.toFixed(3))

  objectProps.rotation.x = Number((object.rotation.x * 180 / Math.PI).toFixed(3))
  objectProps.rotation.y = Number((object.rotation.y * 180 / Math.PI).toFixed(3))
  objectProps.rotation.z = Number((object.rotation.z * 180 / Math.PI).toFixed(3))

  objectProps.scale.x = Number(object.scale.x.toFixed(3))
  objectProps.scale.y = Number(object.scale.y.toFixed(3))
  objectProps.scale.z = Number(object.scale.z.toFixed(3))
}

// 更新场景树数据
const updateSceneTree = () => {
  const treeData: any[] = []

  // 添加场景作为根节点
  const sceneNode = {
    id: 'scene',
    label: '场景',
    children: []
  }

  // 遍历场景中的所有对象
  scene.traverse((object) => {
    if (object === scene) return

    const node = {
      id: object.id,
      label: object.name || `未命名_${object.id}`,
      type: object.type,
      object: object,
      children: []
    }

    // 如果对象有父级且不是场景，则作为子节点
    if (object.parent && object.parent !== scene) {
      const parentNode = findNodeById(sceneNode, object.parent.id)
      if (parentNode) {
        parentNode.children.push(node)
      } else {
        sceneNode.children.push(node)
      }
    } else {
      sceneNode.children.push(node)
    }
  })

  treeData.push(sceneNode)
  sceneTreeData.value = treeData
}

// 根据ID查找节点
const findNodeById = (node: any, id: number): any => {
  if (node.id === id) return node

  if (node.children) {
    for (const child of node.children) {
      const found = findNodeById(child, id)
      if (found) return found
    }
  }

  return null
}

// 创建选择框
const createSelectionBox = (object: THREE.Object3D) => {
  // 移除之前的选择框
  if (selectionBox) {
    scene.remove(selectionBox)
  }

  // 创建包围盒
  const box = new THREE.Box3().setFromObject(object)

  // 创建包围盒辅助对象（绿色框）
  selectionBox = new THREE.Box3Helper(box, new THREE.Color(0x00ff00))
  scene.add(selectionBox)
}

// 选择场景树节点
const handleNodeClick = (data: any) => {
  if (data.id === 'scene') {
    selectedObject.value = null

    // 移除选择框
    if (selectionBox) {
      scene.remove(selectionBox)
      selectionBox = null
    }

    return
  }

  selectedObject.value = data.object
  currentNodeKey.value = data.id

  // 创建选择框
  createSelectionBox(data.object)

  // 更新属性面板
  updateObjectProps(data.object)
}

// 高亮树节点
const highlightTreeNode = (objectId: number) => {
  currentNodeKey.value = objectId

  // 等待下一个 DOM 更新周期，确保树已经渲染
  nextTick(() => {
    if (treeRef.value) {
      // 设置当前选中节点
      treeRef.value.setCurrentKey(objectId)

      // 展开到该节点 - 修复展开节点的方法
      // Element Plus 的树组件没有直接的 expandNode 方法
      // 我们可以通过设置 key 来实现选中
      // 不需要手动展开，因为我们已经设置了 default-expand-all
    }
  })
}

// 在树中查找节点
const findNodeInTree = (id: number) => {
  if (!treeRef.value) return null

  const nodes = treeRef.value.store.nodesMap
  return nodes[id]
}

// 更新对象属性
const updateObjectPosition = () => {
  if (!selectedObject.value) return

  selectedObject.value.position.set(
    objectProps.position.x,
    objectProps.position.y,
    objectProps.position.z
  )

  // 更新选择框
  if (selectionBox) {
    scene.remove(selectionBox)
    createSelectionBox(selectedObject.value)
  }
}

const updateObjectRotation = () => {
  if (!selectedObject.value) return

  selectedObject.value.rotation.set(
    objectProps.rotation.x * Math.PI / 180,
    objectProps.rotation.y * Math.PI / 180,
    objectProps.rotation.z * Math.PI / 180
  )

  // 更新选择框
  if (selectionBox) {
    scene.remove(selectionBox)
    createSelectionBox(selectedObject.value)
  }
}

const updateObjectScale = () => {
  if (!selectedObject.value) return

  selectedObject.value.scale.set(
    objectProps.scale.x,
    objectProps.scale.y,
    objectProps.scale.z
  )

  // 更新选择框
  if (selectionBox) {
    scene.remove(selectionBox)
    createSelectionBox(selectedObject.value)
  }
}

const updateObjectName = () => {
  if (!selectedObject.value) return

  selectedObject.value.name = objectProps.name
  updateSceneTree()
}

// 初始化 Three.js 场景
const initThree = () => {
  if (!canvasRef.value) return

  // 创建场景
  scene = new THREE.Scene()

  // 创建相机
  camera = new THREE.PerspectiveCamera(
    75,
    canvasRef.value.clientWidth / canvasRef.value.clientHeight,
    0.1,
    1000
  )
  camera.position.z = 5

  // 创建渲染器
  renderer = new THREE.WebGLRenderer({
    canvas: canvasRef.value,
    antialias: true
  })
  renderer.setSize(canvasRef.value.clientWidth, canvasRef.value.clientHeight)
  renderer.setClearColor(0x333333)

  // 创建立方体
  const geometry = new THREE.BoxGeometry(2, 2, 2)
  const material = new THREE.MeshNormalMaterial()
  cube = new THREE.Mesh(geometry, material)
  cube.name = "立方体"
  scene.add(cube)

  // 添加灯光
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.8) // 增加环境光强度从0.5到0.8
  scene.add(ambientLight)

  // 添加半球光以提供更自然的环境光照
  const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.6)
  hemisphereLight.position.set(0, 20, 0)
  scene.add(hemisphereLight)

  const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0) // 增加平行光强度从0.8到1.0
  directionalLight.position.set(1, 1, 1)
  directionalLight.castShadow = true // 启用阴影
  scene.add(directionalLight)

  // 添加 OrbitControls
  controls = new OrbitControls(camera, renderer.domElement)
  controls.enableDamping = true
  controls.dampingFactor = 0.05

  // 添加世界坐标轴
  const axesHelper = new THREE.AxesHelper(5) // 参数是坐标轴的长度
  axesHelper.position.set(0, 0.01, 0) // 稍微抬高一点，避免与地面重叠
  // 设置坐标轴为不可点击
  axesHelper.userData.notSelectable = true
  scene.add(axesHelper)
  
  // 添加坐标轴标签
  const createAxisLabel = (text: string, color: THREE.Color) => {
    const canvas = document.createElement('canvas')
    canvas.width = 64
    canvas.height = 64
    
    const context = canvas.getContext('2d')
    if (context) {
      context.fillStyle = '#ffffff'
      context.font = 'Bold 48px Arial'
      context.textAlign = 'center'
      context.textBaseline = 'middle'
      context.fillText(text, 32, 32)
    }
    
    const texture = new THREE.CanvasTexture(canvas)
    const material = new THREE.SpriteMaterial({ 
      map: texture,
      color: color
    })
    
    const sprite = new THREE.Sprite(material)
    sprite.scale.set(0.5, 0.5, 0.5)
    // 设置标签为不可点击
    sprite.userData.notSelectable = true
    return sprite
  }
  
  const xLabel = createAxisLabel('X', new THREE.Color(0xff0000))
  const yLabel = createAxisLabel('Y', new THREE.Color(0x00ff00))
  const zLabel = createAxisLabel('Z', new THREE.Color(0x0000ff))
  
  // 设置标签位置
  xLabel.position.set(5.5, 0.01, 0)
  yLabel.position.set(0, 5.5, 0)
  zLabel.position.set(0, 0.01, 5.5)
  
  // 添加标签到场景
  scene.add(xLabel)
  scene.add(yLabel)
  scene.add(zLabel)

  // 初始化射线投射器和鼠标坐标
  raycaster = new THREE.Raycaster()
  mouse = new THREE.Vector2()

  // 添加点击事件监听
  canvasRef.value.addEventListener('click', onMouseClick)

  // 更新场景树
  updateSceneTree()

  // 开始动画循环
  animate()
}

// 处理鼠标点击事件
const onMouseClick = (event: MouseEvent) => {
  if (!canvasRef.value) return

  // 计算鼠标在归一化设备坐标中的位置
  const rect = canvasRef.value.getBoundingClientRect()
  mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
  mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1

  // 设置射线投射器
  raycaster.setFromCamera(mouse, camera)

  // 获取所有可点击的对象（排除选择框）
  const objects = scene.children.filter(obj => 
    obj !== selectionBox && 
    obj.userData.notSelectable !== true
  )

  // 计算与射线相交的对象
  const intersects = raycaster.intersectObjects(objects, true)

  if (intersects.length > 0) {
    // 检查选中的对象是否可选择
    let selectedObj = intersects[0].object
    
    // 向上遍历父级，检查是否有不可选择的父对象
    let parent = selectedObj
    let isNotSelectable = false
    
    while (parent) {
      if (parent.userData.notSelectable === true) {
        isNotSelectable = true
        break
      }
      parent = parent.parent
    }
    
    if (isNotSelectable) {
      return // 如果对象或其父级被标记为不可选择，则忽略
    }
    
    const object = selectedObj
    console.log('点击的对象:', object)
    console.log('对象名称:', object.name)
    console.log('对象类型:', object.type)
    console.log('对象位置:', object.position)

    // 选中对象
    selectedObject.value = object
    updateObjectProps(object)

    // 创建选择框
    createSelectionBox(object)

    // 高亮树节点
    highlightTreeNode(object.id)
  }
}

// 动画循环
const animate = () => {
  requestAnimationFrame(animate)

  // 旋转立方体
  if (cube && !loadedModel) {
    cube.rotation.x += 0.01
    cube.rotation.y += 0.01
  }

  // 更新 OrbitControls
  controls.update()

  // 渲染场景
  renderer.render(scene, camera)
}

// 处理窗口大小变化
const handleResize = () => {
  if (!canvasRef.value || !camera || !renderer) return

  camera.aspect = canvasRef.value.clientWidth / canvasRef.value.clientHeight
  camera.updateProjectionMatrix()
  renderer.setSize(canvasRef.value.clientWidth, canvasRef.value.clientHeight)
}

// 导入模型
const importModel = () => {
  importDialogVisible.value = true
}

function addScene(gltfScene) {
  if (cube) {
    scene.remove(cube)
  }
  // 移除之前加载的模型
  if (loadedModel) {
    scene.remove(loadedModel)
  }

  // 添加新模型
  loadedModel = gltfScene
  loadedModel.name = "导入的模型"

  // 为模型中的所有网格添加名称
  loadedModel.traverse((child) => {
    if (child.isMesh) {
      child.name = child.name || `模型部件_${child.id}`
    }
  })

  // 计算模型包围盒以调整大小
  const box = new THREE.Box3().setFromObject(loadedModel)
  const size = box.getSize(new THREE.Vector3())
  const maxDim = Math.max(size.x, size.y, size.z)
  const scale = 3 / maxDim // 调整模型大小以适应场景

  loadedModel.scale.set(scale, scale, scale)

  // 居中模型
  const center = box.getCenter(new THREE.Vector3())
  loadedModel.position.x = -center.x * scale
  loadedModel.position.y = -center.y * scale
  loadedModel.position.z = -center.z * scale

  scene.add(loadedModel)

  // 更新场景树
  updateSceneTree()

  ElMessage.success('模型加载成功')
  isLoading.value = false
  importDialogVisible.value = false
}

// 确认导入模型
const confirmImport = () => {
  if (!modelPath.value) {
    ElMessage.warning('请输入模型路径')
    return
  }

  isLoading.value = true
  const loader = new GLTFLoader()

  loader.load(
    modelPath.value,
    (gltf) => {

      addScene(gltf.scene)
    },
    (xhr) => {
      console.log((xhr.loaded / xhr.total * 100) + '% 已加载')
    },
    (error) => {
      console.error('加载模型出错:', error)
      ElMessage.error('加载模型失败: ' + error.message)
      isLoading.value = false
    }
  )
}

// 导出模型
const exportModel = () => {
  ElMessage.info('导出模型功能正在开发中...')
}

// 添加更新对象可见性的函数 - 确保这个函数在 script 标签内部
const updateObjectVisibility = () => {
  if (!selectedObject.value) return

  selectedObject.value.visible = objectProps.visible

  // 更新选择框
  if (selectionBox) {
    if (!objectProps.visible) {
      scene.remove(selectionBox)
      selectionBox = null
    } else {
      createSelectionBox(selectedObject.value)
    }
  }

  // 更新树节点显示状态
  updateSceneTree()
}

// 组件挂载后初始化 Three.js
onMounted(() => {
  initThree()
  window.addEventListener('resize', handleResize)
})

const handleSceneLoaded = (scene) => {
  console.log("Scene received from component:", scene);
  loadError.value = null;
  addScene(scene)
};

const handleLoading = (isLoading) => {
  loadingStatus.value = isLoading;
  if (isLoading) {
    loadError.value = null; // Clear error when loading starts
  }
};

const handleError = (error) => {
  console.error("Error received from component:", error);
  loadError.value = error.message || 'An unknown error occurred.';
};

</script>

<template>
  <div class="app-container">
    <!-- 左侧场景树 -->
    <div class="sidebar left-sidebar">
      <h3>场景层级</h3>
      <el-tree ref="treeRef" :data="sceneTreeData" :props="{ children: 'children', label: 'label' }"
        @node-click="handleNodeClick" :highlight-current="true" :current-node-key="currentNodeKey" node-key="id"
        default-expand-all />
    </div>


    <!-- 中间内容区 -->
    <div class="main-content">
      <div class="top-menu">
        <el-button type="primary" @click="importModel">导入模型</el-button>
        <el-button type="success" @click="exportModel">导出模型</el-button>
      </div>

      <div class="three-container">
        <canvas ref="canvasRef" class="three-canvas"></canvas>
      </div>
    </div>

    <!-- 右侧属性面板 -->
    <div class="sidebar right-sidebar">
      <h3>属性面板</h3>
      <el-form v-if="selectedObject" label-position="left" size="small" label-width="80px">
        <el-form-item label="名称">
          <el-input v-model="objectProps.name" @change="updateObjectName" size="small" />
        </el-form-item>

        <el-form-item label="类型">
          <el-input v-model="objectProps.type" disabled size="small" />
        </el-form-item>

        <el-form-item label="显示">
          <el-switch v-model="objectProps.visible" @change="updateObjectVisibility" active-text="显示" inactive-text="隐藏"
            size="small" />
        </el-form-item>

        <el-form-item label="位置 X">
          <el-input-number v-model="objectProps.position.x" :step="0.1" @change="updateObjectPosition" size="small"
            style="width: 100%" />
        </el-form-item>
        <el-form-item label="位置 Y">
          <el-input-number v-model="objectProps.position.y" :step="0.1" @change="updateObjectPosition" size="small"
            style="width: 100%" />
        </el-form-item>
        <el-form-item label="位置 Z">
          <el-input-number v-model="objectProps.position.z" :step="0.1" @change="updateObjectPosition" size="small"
            style="width: 100%" />
        </el-form-item>

        <el-form-item label="旋转 X (度)">
          <el-input-number v-model="objectProps.rotation.x" :step="5" @change="updateObjectRotation"
            style="width: 100%" />
        </el-form-item>
        <el-form-item label="旋转 Y (度)">
          <el-input-number v-model="objectProps.rotation.y" :step="5" @change="updateObjectRotation"
            style="width: 100%" />
        </el-form-item>
        <el-form-item label="旋转 Z (度)">
          <el-input-number v-model="objectProps.rotation.z" :step="5" @change="updateObjectRotation"
            style="width: 100%" />
        </el-form-item>

        <el-form-item label="缩放 X">
          <el-input-number v-model="objectProps.scale.x" :step="0.1" @change="updateObjectScale" style="width: 100%" />
        </el-form-item>
        <el-form-item label="缩放 Y">
          <el-input-number v-model="objectProps.scale.y" :step="0.1" @change="updateObjectScale" style="width: 100%" />
        </el-form-item>
        <el-form-item label="缩放 Z">
          <el-input-number v-model="objectProps.scale.z" :step="0.1" @change="updateObjectScale" style="width: 100%" />
        </el-form-item>
      </el-form>
      <div v-else class="no-selection">
        未选中任何对象
      </div>
    </div>

    <!-- 导入模型对话框 -->
    <el-dialog v-model="importDialogVisible" title="导入模型" width="30%" :close-on-click-modal="false">
      <el-input v-model="modelPath" placeholder="请输入GLTF模型路径" :disabled="isLoading" />
      <GltfZipLoader gltf-path-in-zip="scene.gltf" :show-preview="false" preview-height="400px"
        @scene="handleSceneLoaded" @loading="handleLoading" @error="handleError" />

      <template #footer>
        <span class="dialog-footer">
          <el-button @click="importDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="confirmImport" :loading="isLoading">
            确定
          </el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<style scoped>
.app-container {
  display: flex;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

.sidebar {
  width: 250px;
  height: 100vh;
  background-color: #f5f7fa;
  padding: 15px;
  overflow-y: auto;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

.left-sidebar {
  border-right: 1px solid #e6e6e6;
}

.right-sidebar {
  border-left: 1px solid #e6e6e6;
}

.main-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.top-menu {
  padding: 15px;
  display: flex;
  justify-content: center;
  gap: 10px;
  background-color: #f5f7fa;
  border-bottom: 1px solid #e6e6e6;
}

.three-container {
  flex: 1;
  position: relative;
}

.three-canvas {
  width: 100%;
  height: 100%;
  display: block;
}

h3 {
  margin-top: 0;
  margin-bottom: 15px;
  padding-bottom: 10px;
  border-bottom: 1px solid #e6e6e6;
}

.prop-group {
  display: flex;
  gap: 5px;
}

.prop-group :deep(.el-input-number) {
  width: 100%;
}

.no-selection {
  color: #909399;
  text-align: center;
  margin-top: 20px;
}

/* 添加树节点高亮样式 */
:deep(.el-tree-node.is-current > .el-tree-node__content) {
  background-color: #e6f7ff !important;
  color: #1890ff !important;
  font-weight: bold;
}
</style>